package com.net.io.nio.three.component.buffer;

import java.nio.ByteBuffer;

/**
 * @author zhangtengfei
 * @date 2022/1/28 10:23
 */
public class BufferMethod {
    public static void main(String[] args) {
        System.out.println("------Test get and put-------------");
        ByteBuffer buffer = ByteBuffer.allocate(32);
        buffer.put((byte) 'a')
                .put((byte) 'b')
                .put((byte) 'c')
                .put((byte) 'd')
                .put((byte) 'e')
                .put((byte) 'f');
        System.out.println("before flip()" + buffer);   // [pos=6 lim=32 cap=32]
        // 转换为读取模式
        buffer.flip();
        System.out.println("before get():" + buffer);   // [pos=0 lim=6 cap=32]
        System.out.println((char) buffer.get());        // a
        System.out.println("after get():" + buffer);    // [pos=1 lim=6 cap=32]

        // position移动两位
        byte[] dst = new byte[10];
        buffer.get(dst, 0, 2);
        System.out.println("after get(dst, 0, 2):" + buffer);   // [pos=3 lim=6 cap=32]
        System.out.println("dst:" + new String(dst));           // bc        

        /**
         * put(int index, byte b)	绝对写，向 byteBuffer 底层的 bytes 中下标为 index 的位置插入byte b，不改变 position 的值。
         * get(int index)           绝对读，读取 byteBuffer 底层的 bytes 中下标为 index 的 byte，不改变 position。
         */
        System.out.println((char) buffer.get(2));               // c
        // get(index)不影响position的值; get() 会影响position的值
        System.out.println("after get(index):" + buffer);       //[pos=3 lim=6 cap=32] ？？？？？？？？

        //绝对读写
        System.out.println("--------Test 绝对读写-------");
        ByteBuffer bb = ByteBuffer.allocate(32);
        System.out.println("before put(byte):" + bb);               // [pos=0 lim=32 cap=32]
        System.out.println("after put(byte):" + bb.put((byte) 'z'));// [pos=1 lim=32 cap=32]
        // put(2,(byte) 'c')不改变position的位置
        bb.put(2, (byte) 'c');
        System.out.println("after put(2,(byte) 'c'):" + bb);        // [pos=1 lim=32 cap=32]
        String bbStr = new String(bb.array());
        System.out.println(bbStr);                                  // zc zc之间有空字符串                             

        /**
         *  clear()方法，position 将被设回 0，limit 被设置成 capacity 的值。
         *  换句话说，Buffer 被清空了。Buffer 中的数据并未清除，只是这些标记告诉我们可以从哪里开始往Buffer 里写数据。
         */
        System.out.println("--------Test Clear And Compact--------");
        ByteBuffer buffer2 = ByteBuffer.allocate(32);
        buffer2.put((byte) 'x');
        System.out.println("before clear:" + buffer2);      // [pos=1 lim=32 cap=32]
        buffer2.clear();
        System.out.println("after clear:" + buffer2);       // [pos=0 lim=32 cap=32]
        System.out.println(new String(buffer2.array()));
        //放入4个字节，position移动到下个可写入的位置，也就是4
        buffer2.put("abcd".getBytes());
        System.out.println("before compact:" + buffer2);    // [pos=4 lim=32 cap=32]
        buffer2.flip();
        System.out.println("after flip:" + buffer2);        // [pos=0 lim=4 cap=32]
        /**
         * 如果 Buffer 中仍有未读的数据，且后续还需要这些数据，但是此时想要先先写些数据， 那么使用 compact()方法。
         * compact()方法将所有未读的数据拷贝到 Buffer 起始处。然后将 position 设到最后一个未读元素正后面。
         * limit 属性依然像 clear()方法一样，设置成 capacity。现在 Buffer 准备好写数据了，但是不会覆盖未读的数据。
         */
        System.out.println("还有数据未读，个数:" + buffer2.remaining());// 4
        buffer2.compact();
        System.out.println("after compact:" + buffer2);     // [pos=4 lim=32 cap=32]
        System.out.println(new String(buffer2.array()));    //abcd                            

        /**
         * Buffer.rewind()将 position 设回 0，所以你可以重读 Buffer 中的所有数据。
         * limit 保持不变，仍然表示能从 Buffer 中读取多少个元素（byte、char 等）
         */
        System.out.println("--------Test rewind--------");
        buffer.clear();
        buffer.position(10);
        buffer.limit(15);
        System.out.println("before rewind:" + buffer);      // [pos=10 lim=15 cap=32]
        buffer.rewind();
        System.out.println("before rewind:" + buffer);      // [pos=0 lim=15 cap=32]

        /**
         * 通过调用 Buffer.mark()方法，可以标记 Buffer 中的一个特定 position。之后可以通过调用 Buffer.reset()方法恢复到这个 position。
         */
        System.out.println("--------Test mark AND reset----------");
        buffer = ByteBuffer.allocate(20);
        System.out.println("buffer = " + buffer);       // [pos=0 lim=20 cap=20]
        buffer.clear();
        buffer.position(5);
        buffer.mark();
        buffer.position(10);
        System.out.println("before reset:" + buffer);   // [pos=10 lim=20 cap=20]
        buffer.reset();
        System.out.println("after reset:" + buffer);    // [pos=5 lim=20 cap=20]
    }
}
